package com.silverbox.core.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.alibaba.fastjson.JSONObject;

/**
 * 集合工具类
 * 
 * @author YaoXuYang
 * @date 2017年12月18日
 * @description
 */
public class Utils {

	public static final char UNDERLINE='_';
	public static final String TO_UNDERLINE = "1";
	public static final String TO_HUMP = "2";
	
	public static boolean isEmpty(String str) {
		if ((str == null) || ("".equals(str)) || ("null".equals(str.toLowerCase()))) {
			return true;
		}
		String pattern = "\\S";
		Pattern p = Pattern.compile(pattern, 34);
		Matcher m = p.matcher(str);
		return !m.find();
	}
	
	public static boolean isEmpty(Object obj) {
		if ((obj == null) || ("".equals(obj)) || ("null".equals(obj))) {
			return true;
		}
		return false;
	}

	public static boolean isEmpty(Collection<?> col) {
		if ((null == col) || (col.isEmpty())) {
			return true;
		}
		return false;
	}

	public static boolean isEmpty(Map<?, ?> map) {
		if ((null == map) || (map.isEmpty())) {
			return true;
		}
		return false;
	}

	/**
	 * 判断指定的对象数组是否为空
	 * 
	 * @param objArr
	 *            对象数组
	 * @return [参数说明]
	 * 
	 * @return boolean [返回类型说明]
	 * @exception throws
	 *                [违例类型] [违例说明]
	 * @see [类、类#方法、类#成员]
	 */
	public static boolean isEmpty(Object[] objArr) {
		if ((null == objArr) || (objArr.length < 1)) {
			return true;
		}
		return false;
	}

	/**
	 * 新订单号生成规则(订单总长度为27位纯数字)，+为连接符 fore=年月日时分秒（14位） shopId=8位，不够前面补0 00009356
	 * rand=5位 base=shopId+rand base1=base>>2 右移两位 base2=base^base1 与右移后按位异或
	 * orderNum=fore+base2
	 * 
	 * @param shopId
	 * @return
	 */
	public synchronized static String createOrderNum(Integer shopId) {
		String fore = CalendarUtil.format2yyyyMMddHHmmss(new Date());
		long rand = 0L;
		while (rand < 10000) {
			rand = (long) (Math.random() * 100000);
		}
		String base = shopId + "" + rand;
		long base1 = Long.valueOf(base) >> 2;
		String base2 = String.format("%0" + 13 + "d", (Long.valueOf(base)) ^ base1);
		String ordernum = fore + base2;
		return ordernum;
	}

	@SuppressWarnings("unchecked")
	public static <T> T deepCloneObject(T obj) {
		try {
			ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
			ObjectOutputStream out = new ObjectOutputStream(byteOut);
			out.writeObject(obj);

			ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
			ObjectInputStream in = new ObjectInputStream(byteIn);
			return (T) in.readObject();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * json对象转map
	 * 
	 * @param jo
	 * @return
	 */
	public static Map<String, String> jsonToMap(JSONObject jo) {
		Map<String, String> result = new HashMap<String, String>();
		Set<String> keySet = jo.keySet();
		for (String key : keySet) {
			result.put(key, jo.getString(key));
		}
		return result;
	}
	
	/** 
     * 大陆手机号码11位数，匹配格式：前2位固定格式+后8位任意数 
     * 此方法中前三位格式有： 
     * 13+任意数 
     * 15+任意数 
     * 18+任意数 
     * 17+任意数 
     * 14+任意数
     */  
    public static boolean isChinaPhoneLegal(String str){  
        String regExp = "^((13[0-9])|(15[0-9])|(18[0-9])|(17[0-8])|(14[0-9]))\\d{8}$";  
        Pattern p = Pattern.compile(regExp);  
        Matcher m = p.matcher(str);  
        return m.matches();
    } 
    
    /**
	 * 记录异常堆栈详情
	 * 
	 * @param e
	 * @return
	 */
	public static String log4jDetail(Throwable e) {
		try {
			StringWriter sw = new StringWriter();
			PrintWriter pw = new PrintWriter(sw);
			e.printStackTrace(pw);
			return sw.toString();
		} catch (Exception e2) {
			e.printStackTrace();
		}
		return "服务忙";
	}
	
	/**
     * 拼接订单序号，不足4位补足
     * @param orderSeq
     * @return
     */
    public static String getOrderSeq(Integer orderSeq) {
		if (null == orderSeq) {
			return "0000";
		} else {
			String orderSeqStr = String.valueOf(orderSeq);
			if (orderSeqStr.length() == 1) {
				return "000" + orderSeqStr;
			} else if (orderSeqStr.length() == 2) {
				return "00" + orderSeqStr;
			} else if (orderSeqStr.length() == 3) {
				return "0" + orderSeqStr;
			} else {
				return orderSeqStr;
			}
		}
	}
    
    /**
     * 新17位取餐码生成规则(订单总长度为17位，16位纯数字加上首字母)，+为连接符
     * orderCode = 订单来源（1位）示例 A
     * fore = 年月日（6位）示例 20181122
     * machineId = 机器编号（6位）示例 123456
     * takeMealNum = 取餐号 （4位）示例 0001
     * @param
     * @return takeMealCode 示例 A201811221234560001
     */
    public synchronized static String createTakeMealCode(String machineId, String takeMealNum, String orderCode){
        String fore = CalendarUtil.format3yyMMdd(new Date());
        String srtMachineId = "";
        if (null == machineId) {
        	srtMachineId = "000000";
    	} else {
    		if (machineId.length() == 1) {
    			srtMachineId = "00000" + machineId;
    		} else if (machineId.length() == 2){
    			srtMachineId =  "0000" + machineId;
    		} else if (machineId.length() == 3){
    			srtMachineId = "000" + machineId;
    		} else if (machineId.length() == 4){
    			srtMachineId = "00" + machineId;
    		} else if (machineId.length() == 5){
    			srtMachineId = "0" + machineId;
    		} else {
    			srtMachineId = machineId;
    		}
    	}
        String takeMealCode = orderCode + srtMachineId + fore + takeMealNum;
        return takeMealCode;
    }
    
	/**
	 * 递归转换Map/JSONObject里的字段名写法
	 * 
	 * @param map
	 *            需要转换的map
	 * @param resultMap
	 *            转换后的新map
	 * @param ignoreKeys
	 *            需要忽略的key
	 * @param shiftType
	 *            转换类型(1：转为下划线，2：转为驼峰)
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static void tranferKeyToUnderline(Map<String, Object> map, Map<String, Object> resultMap,
			Set<String> ignoreKeys, String shiftType) {
		Set<Map.Entry<String, Object>> entries = map.entrySet();
		for (Map.Entry<String, Object> entry : entries) {
			String key = entry.getKey();
			Object value = entry.getValue();
			if (ignoreKeys != null && ignoreKeys.contains(key)) {
				resultMap.put(key, value);
				continue;
			}
			String newkey = "";
			if (shiftType.equals(TO_UNDERLINE)) {
				newkey = camelToUnderline(key);
			} else if (shiftType.equals(TO_HUMP)) {
				newkey = camelToHump(key);
			} else {
				return;
			}
			if ((value instanceof List)) {
				List newList = new ArrayList();
				List valList = (List) value;
				for (Object val : valList) {
					if (val instanceof Map) {
						Map<String, Object> subResultMap = new HashMap<String, Object>();
						tranferKeyToUnderline((Map) val, subResultMap, ignoreKeys, shiftType);
						newList.add(subResultMap);
					} else {
						newList.add(val);
					}
				}
				resultMap.put(newkey, newList);
			} else if (value instanceof Map) {
				Map<String, Object> subResultMap = new HashMap<String, Object>();
				Map<String, Object> valMap = (Map<String, Object>) value;
				tranferKeyToUnderline(valMap, subResultMap, ignoreKeys, shiftType);
				resultMap.put(newkey, subResultMap);
			} else {
				resultMap.put(newkey, value);
			}
		}
	}
 
	/**
	 * 将一个字符串由驼峰转为下划线
	 * 
	 * @param param
	 * @return
	 */
	public static final String camelToUnderline(String param) {
		if (param == null || "".equals(param.trim())) {
			return "";
		}
		int len = param.length();
		StringBuilder sb = new StringBuilder(len);
		for (int i = 0; i < len; i++) {
			char c = param.charAt(i);
			if (Character.isUpperCase(c)) {
				if (i != 0) {
					sb.append(UNDERLINE);
				}
				sb.append(Character.toLowerCase(c));
			} else {
				sb.append(c);
			}
		}
		return sb.toString();
	}

	/**
	 * 将一个字符串由下划线转为驼峰
	 * 
	 * @param param
	 * @return
	 */
	public static final String camelToHump(String param) {
		if (param == null || "".equals(param.trim())) {
			return "";
		}
		String[] key_strs = param.split("_");
		StringBuilder sb = new StringBuilder();
		if (key_strs.length > 1) {
			for (int i = 0; i < key_strs.length; i++) {
				String ks = key_strs[i];
				if (!"".equals(ks)) {
					ks = ks.toLowerCase();
					if (i == 0) {
						sb.append(ks);
					} else {
						// ASCII表中65-106是A-Z，97-122是a-z
						int c = ks.charAt(0);
						if (c >= 97 && c <= 122) {
							int v = c - 32;
							sb.append((char) v);
							if (ks.length() > 1) {
								sb.append(ks.substring(1));
							}
						} else {
							sb.append(ks);
						}
					}
				}
			}
			return sb.toString();
		}
		return param;
	}
	/**
	 * 获取当前时间指定具体时间（around=0 获取当前时间之前的时间，around=1 获取当前时间之后的时间），（type=1 分钟，type=2 小时，type=3 天）
	 * @param count
	 * @param around
	 * @param type
	 * @param dateTime
	 * @return 
	 */
	public static String getBeforeAndAfterTimeByParam(int count,int around,int type,Date dateTime){ 
	    String str = ""; 
	    Calendar calendar = Calendar.getInstance();
	    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	    if(null != dateTime){
			calendar.setTime(dateTime);
	    }
	    count = around == 1?count:(-count);
	    int calendarType = type == 1?Calendar.MINUTE:(type == 2?Calendar.HOUR:Calendar.DATE);
	    calendar.set(calendarType, calendar.get(calendarType) + count);
	    str = sdf.format(calendar.getTime()); 
	    return str; 
	}
	
	/**
	 * 生成32位随机的UUID
	 * @return
	 */
	public static String createUUID(){
		return  UUID.randomUUID().toString().replaceAll("-", "");
	}
	
	/**
	 * 获取扫码进入的客户端类型	-1：异常，0：其它，1：支付宝，2：口碑，3：微信
	 * @param userAgent
	 * @return
	 */
	public static Integer getClientType(String userAgent){
		if(Utils.isEmpty(userAgent)){
			return -1;
		}
		//将字符串全部转换成大写的
		String clientType = userAgent.toUpperCase();
		if(clientType.indexOf("ALIPAYCLIENT")!=-1 && clientType.indexOf("KOUBEICLIENT")==-1){
			return 1;
		}else if(clientType.indexOf("KOUBEICLIENT")!=-1){
			return 2;
		}else if(clientType.indexOf("MICROMESSENGER")!=-1){
			return 3;
		}else{
			return 0;
		}
	}
    public static Integer getReserveOrderSeq(Integer oldOrderSeq, String reserveDate) {
    	Integer reserveOrderSeq = oldOrderSeq;
    	if (!isEmpty(reserveDate) && null!=oldOrderSeq) {
    		String nowDate = CalendarUtil.formatDateByString(new Date());
    		if (!reserveDate.equals(nowDate)) {
    			reserveOrderSeq = oldOrderSeq + 1000;
    		}
    	}
    	return reserveOrderSeq;
    }

    /**
     * 是否匹配时间段模版
     * @param date
     * @param week
     * @param startTime
     * @param endTime
     * @return
     */
    public static boolean matchTimeTemplate(Date date, String week, String startTime, String endTime) {
        String dateStr = CalendarUtil.format2String(date);
        if(week.contains(dayForWeek(date).toString()) && timeBetween(dateStr, startTime, endTime)){
            return true;
        }else{
            return false;
        }
    }

    /**
     * 判断传入时间是否在开始时间和结束时间之间
     * ①如果开始时间为00:00，结束时间为23:59，表示一整天，直接返回true
     * ②开始时间必须小于结束时间，并且没有跨天概念
     * @param date
     * @param startTime
     * @param endTime
     * @return
     */
    public static boolean timeBetween(String date, String startTime, String endTime) {
        if ("00:00".equals(startTime) && "23:59".equals(endTime)) {
            return true;
        }
        String nowDay = date.substring(0, 10);
        startTime = nowDay + " " +  startTime + ":00";
        endTime = nowDay + " " +  endTime + ":00";
        Date nowDate = CalendarUtil.formatByTime(date);
        Date startDate = CalendarUtil.formatByTime(startTime);
        Date endDate = CalendarUtil.formatByTime(endTime);
        if(nowDate.after(startDate) && nowDate.before(endDate)){
            return true;
        }else{
            return false;
        }
    }
    //判断传入时间属于星期几
    public static Integer dayForWeek(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        Integer dayForWeek = 1 ;
        if (c.get(Calendar.DAY_OF_WEEK) == 1 ) {
            dayForWeek = new Integer(7) ;  //星期日
        } else {
            dayForWeek = new Integer(c.get(Calendar.DAY_OF_WEEK) - 1) ;
        }
        return dayForWeek;
    }

    public static String createOrderNumV2(Integer shopId) {
        String fore = CalendarUtil.format2yyyyMMddHHmmss(new Date());
        long rand = 0L;
        while(rand<10000){
            rand = (long)(Math.random() * 100000);
        }
        String base = shopId+ "" + rand;
        long base1 = Long.valueOf(base)>>2;
        String base2 = String.format("%0" + 13 + "d", (Long.valueOf(base))^base1);
        String ordernum = fore + base2;
        return ordernum;
    }
    //获取昨天开始时间
    public static String getYesterdayStartTime() {
        String result = "";
        Calendar c = Calendar.getInstance();
        c.add(Calendar.DAY_OF_MONTH, -1);
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE,0);
        c.set(Calendar.SECOND, 0);
        Date date = c.getTime();
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        result = format.format(date);
        return result;
    }
    //获取今天开始时间
    public static String getTodayStartTime() {
        String result = "";
        Calendar c = Calendar.getInstance();
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE,0);
        c.set(Calendar.SECOND, 0);
        Date date = c.getTime();
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        result = format.format(date);
        return result;
    }
    //获取今天结束时间
    public static String getTodayEndTime() {
        String result = "";
        Calendar c = Calendar.getInstance();
        c.add(Calendar.DAY_OF_MONTH, 1);
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE,0);
        c.set(Calendar.SECOND, 0);
        Date date = c.getTime();
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        result = format.format(date);
        return result;
    }
}
